
import java.net.Socket;
import java.io.*;
public class PI extends Thread{
    

    public PI(Socket s) {
        this.ccs = s;
        try {
            ccin = new BufferedReader(new InputStreamReader(ccs.getInputStream()));
            ccout = new PrintStream(ccs.getOutputStream());
        } catch(Exception e) {
            print(e);
        }
    }

    public void print(Object st, Object... args) {
    
    }

    private void closeConnections() {
        try {
            if(ccin!=null)
                ccin.close();
            if (ccout!=null)
                ccout.close();
            ccs.close();
        } catch(Exception e) {}
        print("command conn closed.");
    }
    public void run() {
        try {
            if(login()); {
                
                logged();
                
            }
            
        }catch(Exception e) {
            print(e);
        }
        print("###Notice### Terminating Thread...");
    }

    public void pnotice(String msg) {
        print("(%s) PI NOTICE: %s\n",userName,msg);
    }

    public void dnotice(String msg) {
        print("(%s) DTP NOTICE: %s\n",userName,msg);
    }

    ///////Folder Related functions

    /**
     * 
     * @return the path of the current directory inside the userRootFolder
     * 
     */


    public String getRelativeWorkingDir() {
        return workingDirectory;
    }

    public void setWorkingDir(String dir) {
        workingDirectory = dir;
        //para convenir que nunk termina con /
       if(workingDirectory.length()> 0 && workingDirectory.charAt(workingDirectory.length()-1) == '/')
           workingDirectory = workingDirectory.substring(0, workingDirectory.length()-2);
       //
    }

    public boolean fileBelongsToUser(File file) {
        try {
            String root = new File(getUserRoot()).getCanonicalPath();
            String f = file.getCanonicalPath();
            if(f.startsWith(root))
                return true;
        } catch(Exception e) {}

        return false;
    }

    public String getRealPath(String arg) {
        if(arg.startsWith("/"))
            return getUserRoot()+arg;
        else
            return getRealWorkingDir()+"/"+arg;
    }

    public String getRootDir() {
        return rootDirectory;
    }

    public String getUserRoot() {
        return getRootDir()+"/"+userName;
    }

    public String getRealWorkingDir() {
        String wd = getRelativeWorkingDir();
        if(wd.length() == 0)
            return getUserRoot();
        else
            return getUserRoot()+wd;
    }

    //User Realated functions


/*
    public boolean userExist(String userName) {
        return true;
    }
    public boolean login(String userName, String pwd) {
        User u = User.get(userName);
        print("---------"+u);
        return u != null && u.pwd == pwd;
        
    }*/
    public String getUserName() {
        return userName;
    }
    public String getUserGroup() {
        return "None";
    }


    


    public void response(String response, Object... args) {
        print("response to "+userName+": "+response+"\r\n", args);
        ccout.printf(response+"\r\n", args);
    }

    public Command readCommand() throws Exception {
        String cmd = ccin.readLine();
        print("command from "+userName+": "+cmd);
        return new Command(cmd);
    }
    public void logout() {}
    public boolean login() throws Exception {
        response("220 Juan File Server version 0.1");
/*        response("220 written by Juan Ruiz juan.jose.rgz@gmail.com");
        response("220 written by Juan Ruiz juan.jose.rgz@gmail.com");//*/
        try {
            while(true) {
                Command cmd = readCommand();



                if(!cmd.equals("USER")) {
                    response("503 Bad sequence of commands.");
                    continue;
                }

                String userNameLogin = cmd.getArgs();

                User loginIn = User.get(userNameLogin);

                if(loginIn == null) {
                    response("332 Need account for login.");
                    continue;
                }

                response("331 Password required for "+loginIn.username);
                cmd = readCommand();
                if(!cmd.equals("PASS")) {
                    response("503 Bad sequence of commands.");
                    continue;
                }
                if(loginIn.pwd.equals(cmd.getArgs())) {
                    userName = loginIn.username;
                    response("230 Logged on, continue");
                    return true;

                }
                response("530 Not Logged in");
            }
        } catch(Exception e){

            if(dtp!=null)
                dtp.closeConnections();
            closeConnections();
            return false;

        }
    }

    public void logged() throws Exception{

        while(true) {
            Command cmd = readCommand();


            if(cmd == null || cmd.equals("QUIT")) {
                response("221 Service closing control connection");
                if(dtp!=null)
                    dtp.closeConnections();
                closeConnections();
                break;
            } else if(cmd.equals("PWD")) {
                String dir = getRelativeWorkingDir();
                if(dir.equals(""))
                    dir = "/";
                response("257 \"%s\" is current directory.",dir);
            } else if (cmd.equals("CWD")) {

                String dir = cmd.getArgs();

                if(dir.startsWith("/"))//absolute dir
                    dir = getUserRoot()+dir;
                //relative dir
                else
                    dir = getRealWorkingDir()+"/"+dir;
                
                File f = new File(dir);
                if(f.exists() && f.isDirectory() && fileBelongsToUser(f)) {
                    String root = new File(getUserRoot()).getCanonicalPath();
                    dir = f.getCanonicalPath().substring(root.length());
                    setWorkingDir(dir);
                    if(dir.equals(""))
                        dir = "/";
                    response("250 current directory changed to '%s'.",dir);
                } else
                    response("550 Directory %s doesnot exist.",cmd.getArgs());

            } else if(cmd.equals("CDUP")){
                String wd = getRelativeWorkingDir();
                if(wd == "") {
                    response("550 there is not an upper level.");
                    continue;
                }
                ///as/sdf/wer
               int i = wd.lastIndexOf("/");
               wd = wd.substring(0, i);
               setWorkingDir(wd);
               response("200 current directory changed to %s.",wd);
            } else if(cmd.equals("MKD")) {

                
                String dir = getRealPath(cmd.getArgs());
                File f = new File(dir);
                print(">>creating directory:"+dir);
                if(fileBelongsToUser(f) && !f.exists() && f.mkdir()) {
                    response("257 folder created successfully.");
                    continue;
                }
                print("%s %s %s\n", fileBelongsToUser(f) , !f.exists() , f.mkdir());
                response("550 could not create directory.");
                
            }else if(cmd.equals("PASV")) {
                try {
                    port = 0;
                    dtp = new DTP(PASSIVE_MODE,host,port, this);
                    dtp.queueCommand(DTP.CONNECT);
               } catch(Exception e) {print(e); e.printStackTrace(); print("PI error");}
            } else if(cmd.equals("PORT")) {
                String args = cmd.getArgs().trim();
                if(args.length()>0) {
                    //args = args.substring(1, args.length()-1);
                    String token[] = args.split(",");
                    if(token.length==6) {
                        String dataConnHost = token[0]+"."+token[1]+"."+token[2]+"."+token[3];
                        try {
                            port = (Integer.parseInt(token[4])<<8)+ Integer.parseInt(token[5]);
                            dtp = new DTP(ACTIVE_MODE,dataConnHost,port,this);
                            dtp.queueCommand(DTP.CONNECT);
                            continue;
                        } catch(Exception e) {print(e); e.printStackTrace(); print("PI error");}
                    }
                }
                response("501 Syntax error in parameters or arguments.");
            } else if (cmd.equals("LIST")) {

             //   if(dtp.isConnected())
               //     response("125 Data connection already open; transfer starting.");
                //else
                    response("150 File status okay; about to open data connection.");
             
                dtp.queueCommand(DTP.LIST);
                

            } else if (cmd.equals("TYPE")) {
                response("200 Type set to "+cmd.getArgs());
            } else if (cmd.equals("SYST")) {
                response("215 UNIX system type.");
            } else if(cmd.equals("RETR")) {
                dtp.queueCommand(DTP.RETR, cmd.getArgs());
            } else if(cmd.equals("STOR")) {
                dtp.queueCommand(DTP.STOR, cmd.getArgs());
            } else if(cmd.equals("DELE")) {
                String path = getRealPath(cmd.getArgs());
                File f = new File(path);
                if(f.exists()) {
                    if(f.delete()){
                        response("250 File %s deleted succesfully.",cmd.getArgs());
                    }else{
                        response("450 File %s delete FAILED.",cmd.getArgs());
                    }
                } else
                    response("550 File %s doesnot exist.",cmd.getArgs());
            } else if (cmd.equals("RMD")) {
                String path = getRealPath(cmd.getArgs());
                File f = new File(path);
                if(f.exists()) {
                    if(f.delete()){
                        response("250 Directory %s deleted succesfully.",cmd.getArgs());
                    }else{
                        if(f.list().length==0)
                            response("450 Directory %s delete FAILED.",cmd.getArgs());
                        else
                            response("450 Directory %s must be empy.",cmd.getArgs());
                    }
                } else
                    response("550 Directory %s doesnot exist.",cmd.getArgs());
            
            } else if(cmd.equals("RNFR")) {
                String path = getRealPath(cmd.getArgs());
                File f = new File(path);
                if(f.exists()) {
                     RNFR = f;
                     response("350 waiting for RNTO.");
                } else {
                    print(path);
                    response("550 File %s doesnot exist.",cmd.getArgs());
                }
            } else if(cmd.equals("RNTO")) {
                // RNFR = f;
                if(RNFR==null)
                    response("503 Bad sequence of commands.");

                String path = getRealPath(cmd.getArgs());
                File RNTO = new File(path);
                if(!RNTO.exists()) {
                    if(RNFR.renameTo(RNTO))
                        response("250 File rename success.") ;
                    else
                        response("553 error while attempting to rename.");
                } else {
                    response("553 %s already exist",cmd.getArgs());
                }

            //FIN
            } else {
                response("502 Command not implemented.");
            }
        }
    }

    /**
     * @return true if the minimun configuration needed has been set to
     * initiate a data connection can be made.
     */
    public boolean dtpConfigurationDone() {
        if(dtpMode==PASSIVE_MODE)
            return true;
        if(port>0 && dataConnHost!=null)
            return true;
        return false;
    }

    Socket ccs;
    BufferedReader ccin;
    PrintStream ccout;
    String userName = "unknown user", workingDirectory = "", type="A", host="127.0.0.1";
    String dataConnHost = null;
    String rootDirectory = "root";
    /**
     * if passive mode, port is the port where the server listens
     * if active mode, the port where the client listens
     */
    int port = -1;
    /**
     * takes the values -1 if unset, or PASSIVE_MODE OR ACTIVE_MODE
     */
    int dtpMode = -1;
    private File RNFR=null;
    DTP dtp;
    final static int PASSIVE_MODE = 0, ACTIVE_MODE = 1;
}

